﻿using System.ComponentModel;

namespace Koala.Pro.CodeGenerator.UI.Controls
{
    public partial class ProgressWindow : Form, IProgressCallback
    {
        public delegate void SetTextInvoker(string text1, string text2);

        public delegate void IncrementInvoker(int val);

        public delegate void StepToInvoker(int val);

        public delegate void RangeInvoker(int minimum, int maximum);

        public delegate void MoreLessInvoker(bool state);

        public delegate void AddMessageInvoker(ProgressMessageTypes type, string message);

        private ManualResetEvent initEvent = new ManualResetEvent(initialState: false);

        private ManualResetEvent abortEvent = new ManualResetEvent(initialState: false);

        private ProgressAutoCloseTypes autoClose;

        private readonly int minWidth = 232;

        private readonly int openSize;

        private readonly int closedSize;

        private bool requiresClose = true;

        private int totalErrors;

        private bool morelessOpen;

        private bool completed;

        public bool IsAborting => abortEvent.WaitOne(0, exitContext: false);

        private bool firstMsg = true;

        public ProgressWindow()
        {
            InitializeComponent();

            openSize = base.Height;
            closedSize = base.Height;
            DoSetMoreLess(moreless: false);
        }

        public void AddMessage(string message)
        {
            Invoke(new AddMessageInvoker(DoAddMessage), ProgressMessageTypes.Info, message);
        }

        public void AddMessage(ProgressMessageTypes type, string message)
        {
            Invoke(new AddMessageInvoker(DoAddMessage), type, message);
        }

        public void Begin(int minimum, int maximum)
        {
            initEvent.WaitOne();
            Invoke(new RangeInvoker(DoBegin), minimum, maximum);
        }

        public void Begin(ProgressAutoCloseTypes autoClose, int minimum, int maximum)
        {
            initEvent.WaitOne();
            this.autoClose = autoClose;
            Invoke(new RangeInvoker(DoBegin), minimum, maximum);
        }

        public void Begin()
        {
            initEvent.WaitOne();
            Invoke(new MethodInvoker(DoBegin));
        }

        public void End()
        {
            if (requiresClose)
            {
                Invoke(new MethodInvoker(DoEnd));
            }
        }

        public void Increment(int val)
        {
            Invoke(new IncrementInvoker(DoIncrement), val);
        }

        public void SetAutoClose(ProgressAutoCloseTypes autoClose)
        {
            this.autoClose = autoClose;
        }

        public void SetRange(int minimum, int maximum)
        {
            initEvent.WaitOne();
            Invoke(new RangeInvoker(DoSetRange), minimum, maximum);
        }

        public void SetText(string text1, string text2)
        {
            Invoke(new SetTextInvoker(DoSetText), text1, text2);
        }

        public void SetText(string text)
        {
            SetText(null, text);
        }

        public void StepTo(int val)
        {
            Invoke(new StepToInvoker(DoStepTo), val);
        }

        private void morelessButton_Click(object sender, EventArgs e)
        {
            Invoke(new MoreLessInvoker(DoSetMoreLess), !morelessOpen);
        }

        private void ProgressWindow_Resize(object sender, EventArgs e)
        {
            if (base.Height < closedSize)
            {
                base.Height = closedSize;
            }
            if (base.Width < minWidth)
            {
                base.Width = minWidth;
            }
         
        }

        private void cancelButton_Click(object sender, EventArgs e)
        {
            Invoke(new SetTextInvoker(DoSetText), null, "Cancelled");
            Invoke(new AddMessageInvoker(DoAddMessage), ProgressMessageTypes.Critical, "Cancelled");
            End();
        }

        private void DoSetText(string text1, string text2)
        {
            if (text1 != null)
            {
                txtMessage1.Text = text1;
            }
            txtMessage2.Text = text2;
        }

        private void DoIncrement(int val)
        {
            progressBar.Increment(val);
            UpdateStatusText();
        }

        private void DoStepTo(int val)
        {
            progressBar.Value = val;
            UpdateStatusText();
        }

        private void DoBegin(int minimum, int maximum)
        {
            DoBegin();
            DoSetRange(minimum, maximum);
        }

        private void DoBegin()
        {
            cancelButton.Enabled = true;
        }

        private void DoSetRange(int minimum, int maximum)
        {
            progressBar.Minimum = minimum;
            progressBar.Maximum = maximum;
            progressBar.Value = minimum;
            UpdateStatusText();
        }

        private void DoAddMessage(ProgressMessageTypes type, string message)
        {
          
            switch (type)
            {
                case ProgressMessageTypes.Info:
                  
                    break;
                case ProgressMessageTypes.Warning:
               
                    totalErrors++;
                    break;
                case ProgressMessageTypes.Critical:
                  
                    totalErrors++;
                    break;
            }
         
        }

        private void DoSetMoreLess(bool moreless)
        {
            morelessOpen = moreless;
            if (moreless)
            {
                base.Height = openSize;
                morelessButton.Text = "<<< 更少";
                base.FormBorderStyle = FormBorderStyle.Sizable;
                base.SizeGripStyle = SizeGripStyle.Show;
            }
            else
            {
                base.Height = closedSize;
                morelessButton.Text = "更多 >>>";
                base.FormBorderStyle = FormBorderStyle.FixedSingle;
                base.SizeGripStyle = SizeGripStyle.Hide;
            }
        }

        private void DoSetCompleted()
        {
            UpdateStatusText();
            completed = true;
            cancelButton.Text = "关闭";
        }

        private void DoEnd()
        {
            if (!completed && requiresClose)
            {
                switch (autoClose)
                {
                    case ProgressAutoCloseTypes.AutoClose:
                        Close();
                        break;
                    case ProgressAutoCloseTypes.WaitOnEnd:
                        Invoke(new MethodInvoker(DoSetCompleted));
                        break;
                    case ProgressAutoCloseTypes.WaitOnError:
                        if (totalErrors == 0)
                        {
                            Close();
                        }
                        else
                        {
                            Invoke(new MethodInvoker(DoSetCompleted));
                        }
                        break;
                }
                if (totalErrors > 0)
                {
                    Invoke(new MoreLessInvoker(DoSetMoreLess), true);
                }
            }
            else
            {
                Close();
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            base.ControlBox = false;
            initEvent.Set();
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            requiresClose = false;
            AbortWork();
            base.OnClosing(e);
        }

        private void UpdateStatusText()
        {
            var a = progressBar.Value * 100 / (progressBar.Maximum - progressBar.Minimum);
            Text = txtMessage1.Text.Trim() + string.Format(" - {0}% 完成", a);
        }

        private void AbortWork()
        {
            abortEvent.Set();
        }
    }
}
